home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / networke / civ-0.000 / civ-0 / civ-0.3 / src / units.cc < prev    next >
C/C++ Source or Header  |  1995-11-15  |  11KB  |  503 lines

  1. #include <string.h>
  2. #include "misc.h"
  3. #include "defs.h"
  4. #include "world.h"
  5. #include "display.h"
  6. #include "trans.h"
  7. #include "units.h"
  8. #include "move.h"
  9. #include "city.h"
  10. #include "player.h"
  11. #include "MsgQ.h"
  12. #include "rules.h"
  13. #include "savefile.h"
  14.  
  15. #include "../pic/armor.xpm"
  16. #include "../pic/artillery.xpm"
  17. #include "../pic/battleship.xpm"
  18. #include "../pic/bomber.xpm"
  19. #include "../pic/cannon.xpm"
  20. #include "../pic/caravan.xpm"
  21. #include "../pic/carrier.xpm"
  22. #include "../pic/catapult.xpm"
  23. #include "../pic/cavalry.xpm"
  24. #include "../pic/chariot.xpm"
  25. #include "../pic/cruiser.xpm"
  26. #include "../pic/diplomat.xpm"
  27. #include "../pic/fighter.xpm"
  28. #include "../pic/frigate.xpm"
  29. #include "../pic/ironclad.xpm"
  30. #include "../pic/knights.xpm"
  31. #include "../pic/legion.xpm"
  32. #include "../pic/mechinf.xpm"
  33. #include "../pic/militia.xpm"
  34. #include "../pic/musketeers.xpm"
  35. #include "../pic/nuclear.xpm"
  36. #include "../pic/phalanx.xpm"
  37. #include "../pic/riflemen.xpm"
  38. #include "../pic/sail.xpm"
  39. #include "../pic/settler.xpm"
  40. #include "../pic/submarine.xpm"
  41. #include "../pic/transport.xpm"
  42. #include "../pic/trireme.xpm"
  43.  
  44. char *names[] = {
  45.   "Armor",
  46.   "Artillery",
  47.   "Battleship",
  48.   "Bomber",
  49.   "Cannon",
  50.   "Caravan",
  51.   "Carrier",
  52.   "Catapult",
  53.   "Cavalry",
  54.   "Chariot",
  55.   "Cruiser",
  56.   "Diplomat",
  57.   "Fighter",
  58.   "Frigate",
  59.   "Ironclad",
  60.   "Knights",
  61.   "Legion",
  62.   "Mech. Infantry",
  63.   "Militia",
  64.   "Musketeers",
  65.   "Nuclear",
  66.   "Phalanx",
  67.   "Riflemen",
  68.   "Sail",
  69.   "Settlers",
  70.   "Submarine",
  71.   "Transport",
  72.   "Trireme"
  73.   };
  74.  
  75. char **pictures[] = {
  76.   armor_xpm,
  77.   artillery_xpm,
  78.   battleship_xpm,
  79.   bomber_xpm,
  80.   cannon_xpm,
  81.   caravan_xpm,
  82.   carrier_xpm,
  83.   catapult_xpm,
  84.   cavalry_xpm,
  85.   chariot_xpm,
  86.   cruiser_xpm,
  87.   diplomat_xpm,
  88.   fighter_xpm,
  89.   frigate_xpm,
  90.   ironclad_xpm,
  91.   knights_xpm,
  92.   legion_xpm,
  93.   mechinf_xpm,
  94.   militia_xpm,
  95.   musketeers_xpm,
  96.   nuclear_xpm,
  97.   phalanx_xpm,
  98.   riflemen_xpm,
  99.   sail_xpm,
  100.   settler_xpm,
  101.   submarine_xpm,
  102.   transport_xpm,
  103.   trireme_xpm
  104.   };
  105.  
  106. int admList[] = {
  107.   10, 5, 3, // armor
  108.   12, 2, 2, // artillery
  109.   18, 12, 4,// battleship
  110.   12, 1, 8, // bomber
  111.   8, 1, 1,  // cannon
  112.   0, 1, 1,  // caravan
  113.   1, 12, 5, // carrier
  114.   6, 1, 1,  // catapult
  115.   2, 1, 2,  // cavalry
  116.   4, 1, 2,  // chariot
  117.   6, 6, 6,  // cruiser
  118.   0, 0, 2,  // diplomat
  119.   4, 2, 10, // fighter
  120.   2, 2, 3,  // frigate
  121.   4, 4, 4,  // ironclad
  122.   4, 2, 2,  // knights
  123.   3, 1, 1,  // legion
  124.   6, 6, 3,  // mech. inf
  125.   1, 1, 1,  // militia
  126.   2, 3, 1,  // musketeers
  127.   99, 0, 16,// nuclear
  128.   1, 2, 1,  // phalanx
  129.   3, 5, 1,  // riflemen
  130.   1, 1, 3,  // sail
  131.   0, 1, 1,  // settlers
  132.   8, 2, 3,  // submarine
  133.   0, 3, 4,  // transport
  134.   1, 0, 3   // trireme
  135.   };
  136.  
  137. long *Unit::compiledPicsArray[MaxUnits];
  138.  
  139. char **Unit::Picture()
  140. {
  141.   return pictures[type];
  142. }
  143.  
  144. int SeaUnit(int type)
  145. {
  146.   switch (type) {
  147.   case BATTLESHIP:
  148.   case CARRIER:
  149.   case CRUISER:
  150.   case FRIGATE:
  151.   case IRONCLAD:
  152.   case SAIL:
  153.   case SUBMARINE:
  154.   case TRANSPORT:
  155.   case TRIREME:
  156.     return 1;
  157.   }
  158.   return 0;
  159. }
  160.  
  161. int AirUnit(int type)
  162. {
  163.   switch (type) {
  164.   case FIGHTER:
  165.   case BOMBER:
  166.     return 1;
  167.   }
  168.   return 0;
  169. }
  170.  
  171. int UnitVisibility(int type)
  172. {
  173.   switch (type) {
  174.   case CARRIER:
  175.   case BATTLESHIP:
  176.   case BOMBER:
  177.   case CRUISER:
  178.   case SUBMARINE:
  179.     return 2;
  180.   }
  181.   return 1;
  182. }
  183.  
  184. int UnitAttack(int type)
  185. {
  186.   return admList[type*3];
  187. }
  188.  
  189. int UnitDefense(int type)
  190. {
  191.   return admList[type*3+1];
  192. }
  193.  
  194. int UnitMoves(int type)
  195. {
  196.   return admList[type*3+2];
  197. }
  198.  
  199. int SettlerOrder(Unit *u, int key)
  200. {
  201.   City *city;
  202.   switch (key) {
  203.   case 'b': // build city
  204.     if (world->WhichCity(u->x, u->y) != 0) return 1;
  205.     city = new City(strdup(*cityNames++), trans->New(), u->x, u->y, playerId);
  206. // city counts as road automatically:
  207.     world->MakeRoad(u->x, u->y);
  208. // auto-irrigate on city square if it is 'clear' type terrain:
  209.     switch (world->Terrain(u->x, u->y)) {
  210.     case GRASS1:
  211.     case GRASS:
  212.     case PLAINS:
  213.     case RIVER:
  214.         world->Irrigate(u->x, u->y);
  215.     }
  216.     *moveQ << PieceMove(city->id, CITY_CREATE, u->x, u->y);
  217.     *moveQ << city->name;
  218.     *moveQ << PieceMove(u->id, PIECE_DIE, 0, 0);
  219.     return 0; // we died
  220.   case 'i': // irrigate
  221.     if ((u->orderProgress = world->IrrigTime(u->x, u->y)) > 0) {
  222.       u->currOrder = 'i';
  223.       u->numMoves = 0;
  224.     }
  225.     break;
  226.   case 'p': // unPollute
  227.     if ((u->orderProgress = world->UnPolluteTime(u->x, u->y)) > 0) {
  228.       u->currOrder = 'p';
  229.       u->numMoves = 0;
  230.     }
  231.     break;
  232.   case 'r': // road
  233.     if (world->IsRailRoad(u->x, u->y)) break; // can't do more
  234.     if (world->IsRoad(u->x, u->y)) { // try to build railroad
  235.       if (Discovered(u->ownerId, "Railroad") &&
  236.       (u->orderProgress = world->RailRoadTime(u->x, u->y)) > 0) {
  237.     u->currOrder = 'r';
  238.     u->numMoves = 0;
  239.       }
  240.       break;
  241.     }
  242.     if (world->Terrain(u->x, u->y) == RIVER &&
  243.     !Discovered(u->ownerId, "Bridge Building")) break;
  244.     if ((u->orderProgress = world->RoadTime(u->x, u->y)) > 0) {
  245.       u->currOrder = 'r';
  246.       u->numMoves = 0;
  247.     }
  248.     break;
  249.   case 'm':
  250.     if (world->Mined(u->x, u->y)) break; // can't do more
  251.     if ((u->orderProgress = world->MineTime(u->x, u->y)) > 0) {
  252.       Debug('u',"Mining at %d %d (%d turns)", u->x, u->y, u->orderProgress);
  253.       u->currOrder = 'm';
  254.       u->numMoves = 0;
  255.     }
  256.     break;
  257.   }
  258.   return 1;
  259. }
  260.  
  261. void SettlerCompleteOrder(Unit *u)
  262. {
  263.   switch (u->currOrder) {
  264.   case 'i':
  265.     if (--u->orderProgress <= 0) {
  266.       world->Irrigate(u->x, u->y);
  267.       u->currOrder = ' ';
  268.     }
  269.     u->numMoves = 0;
  270.     break;
  271.   case 'p':
  272.     if (--u->orderProgress <= 0) {
  273.       world->UnPollute(u->x, u->y);
  274.       u->currOrder = ' ';
  275.     }
  276.     u->numMoves = 0;
  277.     break;
  278.   case 'r':
  279.     if (--u->orderProgress <= 0) {
  280.       if (world->IsRoad(u->x, u->y)) {
  281.     if (Discovered(u->ownerId, "Railroad"))
  282.           world->MakeRailRoad(u->x, u->y);
  283.       }
  284.       else world->MakeRoad(u->x, u->y);
  285.       u->currOrder = ' ';
  286.     }
  287.     u->numMoves = 0;
  288.     break;
  289.   case 'm':
  290.     if (--u->orderProgress <= 0) {
  291.       world->Mine(u->x, u->y);
  292.       u->currOrder = ' ';
  293.     }
  294.     u->numMoves = 0;
  295.     break;
  296.   }
  297. }    
  298.  
  299. Unit *NewUnit(int type, int owner, ulong id, int vet, ulong city, int x, int y)
  300. {
  301.   Debug('u', "Creating new Unit id %ld, owner %d, at %d %d\n", id, owner, x, y);
  302.   Unit *unit = new Unit(owner, id, vet, city, x, y, type);
  303.   trans->SetPtr(unit->id, unit);
  304.   Debug('u', "Doing display for new Unit\n");
  305.   if (owner == playerId) {
  306.     display->ShowPiece(unit->x, unit->y, unit->id);
  307.     world->SeeSquare(unit->x, unit->y, unit->Visibility());
  308.   }
  309.   else
  310.     unit->DrawIfVisible();
  311.   Debug('u', "Done NewUnit for new Unit\n");
  312.   return unit;
  313. }
  314.  
  315. int Unit::Order(int key)
  316. {
  317.   if (key == 'f') {
  318.     currOrder = 'f';
  319.     numMoves = 0;
  320.   }
  321.   else if (key == 's') {
  322.     currOrder = 's';
  323.     numMoves = 0;
  324.   }
  325.   else if (key == ' ')
  326.     numMoves = 0;
  327.   else if (key == 'd') {
  328.     if (type == CARAVAN) {
  329.        City *city = trans->TransCity(world->WhichCity(x,y));
  330.        if (city) city->accProd += 50;
  331.     }
  332.     *moveQ << PieceMove(this->id, PIECE_DIE, 0, 0);
  333.     return 0; // we died
  334.   }
  335.   else if (key == 'u' && carrying) { // wake up cargo
  336.     for (Lister<ulong> l = carrying; l; l.Next()) {
  337.       Unit *ptr = trans->TransUnit(l.Elem());
  338.       ptr->currOrder = ' ';
  339.       ptr->numMoves = UnitMoves(ptr->type);
  340.     }
  341.   }
  342.   else {
  343.     switch (type) {
  344.     case SETTLER:
  345.       return SettlerOrder(this, key);
  346.     }
  347.   }
  348.   return 1;
  349. }
  350.  
  351. void Unit::CompleteOrder()
  352. {
  353.   if (currOrder == 'f') {
  354.     if (!Fortified()) {
  355.       Fortify();
  356.       DrawIfVisible();
  357.       *moveQ << PieceMove(id, UNIT_UPDATE, 1, Veteran() ? 1 : 0);
  358.     }
  359.     numMoves = 0;
  360.   }
  361.   else if (currOrder == 's') // asleep
  362.     numMoves = 0;
  363.   else {
  364.     switch (type) {
  365.     case SETTLER:
  366.       SettlerCompleteOrder(this);
  367.     }
  368.   }
  369. }
  370.  
  371. int Unit::CanMoveOn(int terrainType, int dx, int dy)
  372. {
  373.   // can always move into a city
  374.   // FIXME: actually ought not be able to move seaunits into enemy city
  375.   if (world->WhichCity(dx, dy) != 0 || type == NUCLEAR) return 1;
  376.   if (SeaUnit(type)) return terrainType == WATER;
  377.   if (AirUnit(type)) return 1;
  378.   if (terrainType == WATER) { // check if there is a carrier unit
  379.     // land unit can't move from carrier to carrier
  380.     // so if its already carried fail
  381.     // FIXME? This looks as if it doesnt care whether carrier is your own?!
  382.     if (carriedBy != 0) return 0;
  383.     for (Lister<ulong> unitl = world->Units(dx, dy); unitl; unitl.Next()) {
  384.       Unit *unit = trans->TransUnit(unitl.Elem());
  385.       if (unit->CanCarry(this))
  386.     return 1;
  387.     }
  388.     return 0;
  389.   }
  390.   return 1;
  391. }
  392.     
  393. int Unit::CanAttack(int type)
  394. {
  395.   // sea units can attack other sea units
  396.   // battleships, cruisers, ironclads, frigates can attack coastal units
  397.   switch (type) {
  398.   case BATTLESHIP:
  399.   case IRONCLAD:
  400.   case FRIGATE:
  401.   case CRUISER:
  402.     if (AirUnit(type) || type == NUCLEAR) return 0;
  403.     return 1;
  404.   case CARRIER:
  405.   case SAIL:
  406.   case SUBMARINE:
  407.   case TRIREME:
  408.   case TRANSPORT:
  409.     return SeaUnit(type);
  410.   case FIGHTER:
  411.     return type == BOMBER;
  412.   case BOMBER: // can attack anything except a nuclear or fighter
  413.     if (AirUnit(type) || type == NUCLEAR) return 0;
  414.     return 1;
  415.   }
  416.   if (AirUnit(type) || SeaUnit(type) || type == NUCLEAR || carriedBy != 0)
  417.     return 0;
  418.   return 1;
  419. }
  420.  
  421. double Unit::MoveCost(int terrainType, double movesRem, int sx, int sy,
  422.               int dx, int dy)
  423. {
  424.   if (SeaUnit(type) || AirUnit(type)) return 1;
  425.   double cost;
  426.   if (world->IsRoad(dx, dy))
  427.     cost = 0.333333334;
  428.   else if (world->IsRailRoad(dx, dy))
  429.     cost = 0;
  430.   else {
  431.     switch (terrainType) {
  432.     case MOUNTAINS:
  433.       cost = 3; break;
  434.     case SWAMP:
  435.     case HILLS:
  436.     case FOREST:
  437.     case JUNGLE:
  438.       cost = 2; break;
  439.     case DESERT:
  440.     case PLAINS:
  441.     case GRASS:
  442.     case GRASS1:
  443.     case RIVER:
  444.       cost = 1; break;
  445.     case WATER:
  446.       cost = movesRem;
  447.       break;
  448.     default:
  449.       cost = 1;
  450.       break;
  451.     }
  452.   }
  453.   if ((cost > 1.50001*movesRem) && (movesRem < Moves(players[playerId]->seamoveBonus))) {
  454.       return -1.0; // can't move, too high cost
  455.   }
  456.   return cost;
  457. }
  458.  
  459. int Unit::CanCarry(Unit *unit)
  460. {
  461.   if (unit->ownerId != ownerId) return 0;
  462.   int carryNum = 0, destType = unit->type;
  463.   switch (type) {
  464.   case CARRIER:
  465.     return (AirUnit(destType) || destType == NUCLEAR) && carrying.Count() < 12;
  466.   case FRIGATE:
  467.     carryNum = 4; break;
  468.   case SAIL:
  469.     carryNum = 3; break;
  470.   case TRANSPORT:
  471.     carryNum = 8; break;
  472.   case TRIREME:
  473.     carryNum = 2; break;
  474.   }
  475.   return carryNum > 0 && !AirUnit(destType) && !SeaUnit(destType) &&
  476.     destType != NUCLEAR && carrying.Count() < carryNum;
  477. }
  478.  
  479. void Unit::SetCoord(int xc, int yc)
  480. {
  481.   x = xc;
  482.   y = yc;
  483.   for (Lister<ulong> l = carrying; l; l.Next())
  484.     trans->TransUnit(l.Elem())->SetCoord(x, y);
  485. }
  486.  
  487. void Unit::Save()
  488. {
  489.   WriteULong(id);
  490.   WriteULong(cityId);
  491.   WriteULong(carriedBy);
  492.   WriteUChar(flags);
  493.   WriteUChar(ownerId);
  494.   WriteUShort(x);
  495.   WriteUShort(y);
  496.   WriteUChar(type);
  497.   WriteUChar(currOrder);
  498.   WriteUShort(orderProgress); 
  499.   WriteUShort(carrying.Count());
  500.   for (Lister<ulong> l = carrying; l; l.Next())
  501.     WriteULong(l.Elem());
  502. }
  503.